#ifndef __NODE_VISITOR_H__
#define __NODE_VISITOR_H__

#include "ParseNodes.h"
#include <iostream>
#include <vector>
#include <set>
#include <stack>
#include <fstream>

struct NodeVisitor {
	enum TraverseType { None = 0x0, Pre = 0x1, Post = 0x2, Both = 0x3 };

	NodeVisitor(TraverseType t) : traverseType(t) {}
	TraverseType traverseType;
	TraverseType current_traverse;

	virtual bool Break() { return false; }

	virtual void DefaultVisit(ParseNode *) { }

	/* BASE TYPES */
	virtual void visit(ParseNode *n) { DefaultVisit(n); }
	virtual void visit(ParentNode *n) { DefaultVisit(n); }
	virtual void visit(LeafNode *n) { DefaultVisit(n); }

	/* SPECIFIC TYPES */
	virtual void visit(RootNode *n) { DefaultVisit(n); }
	virtual void visit(CompilationUnitNode *n) { DefaultVisit(n); }
	virtual void visit(PackageDeclarationNode *n) { DefaultVisit(n); }
	virtual void visit(ImportDeclarationsNode *n) { DefaultVisit(n); }
	virtual void visit(ImportDeclarationNode *n) { DefaultVisit(n); }
	virtual void visit(SingleTypeImportDeclarationNode *n) { DefaultVisit(n); }
	virtual void visit(TypeImportOnDemandDeclarationNode *n) { DefaultVisit(n); }
	virtual void visit(ClassDeclarationNode *n) { DefaultVisit(n); }
	virtual void visit(ModifiersNode *n) { DefaultVisit(n); }
	virtual void visit(ModifierNode *n) { DefaultVisit(n); }
	virtual void visit(SuperNode *n) { DefaultVisit(n); }
	virtual void visit(InterfacesNode *n) { DefaultVisit(n); }
	virtual void visit(InterfaceTypeListNode *n) { DefaultVisit(n); }
	virtual void visit(ClassBodyNode *n) { DefaultVisit(n); }
	virtual void visit(ClassBodyDeclarationsNode *n) { DefaultVisit(n); }
	virtual void visit(ClassBodyDeclarationNode *n) { DefaultVisit(n); }
	virtual void visit(ClassMemberDeclarationNode *n) { DefaultVisit(n); }
	virtual void visit(FieldDeclarationNode *n) { DefaultVisit(n); }
	virtual void visit(VariableDeclaratorNode *n) { DefaultVisit(n); }
	virtual void visit(VariableInitializerNode *n) { DefaultVisit(n); }
	virtual void visit(MethodDeclarationNode *n) { DefaultVisit(n); }
	virtual void visit(MethodHeaderNode *n) { DefaultVisit(n); }
	virtual void visit(MethodDeclaratorNode *n) { DefaultVisit(n); }
	virtual void visit(FormalParameterListNode *n) { DefaultVisit(n); }
	virtual void visit(FormalParameterNode *n) { DefaultVisit(n); }
	virtual void visit(MethodBodyNode *n) { DefaultVisit(n); }
	virtual void visit(ConstructorDeclarationNode *n) { DefaultVisit(n); }
	virtual void visit(ConstructorDeclaratorNode *n) { DefaultVisit(n); }
	virtual void visit(ConstructorBodyNode *n) { DefaultVisit(n); }
	virtual void visit(InterfaceDeclarationNode *n) { DefaultVisit(n); }
	virtual void visit(ExtendsInterfacesNode *n) { DefaultVisit(n); }
	virtual void visit(InterfaceBodyNode *n) { DefaultVisit(n); }
	virtual void visit(InterfaceMemberDeclarationsNode *n) { DefaultVisit(n); }
	virtual void visit(InterfaceMemberDeclarationNode *n) { DefaultVisit(n); }
	virtual void visit(AbstractMethodDeclarationNode *n) { DefaultVisit(n); }
	virtual void visit(BlockNode *n) { DefaultVisit(n); }
	virtual void visit(BlockStatementsNode *n) { DefaultVisit(n); }
	virtual void visit(BlockStatementNode *n) { DefaultVisit(n); }
	virtual void visit(LocalVariableDeclarationStatementNode *n) { DefaultVisit(n); }
	virtual void visit(LocalVariableDeclarationNode *n) { DefaultVisit(n); }
	virtual void visit(StatementNode *n) { DefaultVisit(n); }
	virtual void visit(StatementNoShortIfNode *n) { DefaultVisit(n); }
	virtual void visit(StatementWithoutTrailingSubstatementNode *n) { DefaultVisit(n); }
	virtual void visit(EmptyStatementNode *n) { DefaultVisit(n); }
	virtual void visit(ExpressionStatementNode *n) { DefaultVisit(n); }
	virtual void visit(StatementExpressionNode *n) { DefaultVisit(n); }
	virtual void visit(IfStatementNode *n) { DefaultVisit(n); }
	virtual void visit(IfThenStatementNode *n) { DefaultVisit(n); }
	virtual void visit(IfThenElseStatementNode *n) { DefaultVisit(n); }
	virtual void visit(IfThenElseStatementNoShortIfNode *n) { DefaultVisit(n); }
	virtual void visit(WhileStatementNode *n) { DefaultVisit(n); }
	virtual void visit(WhileStatementNoShortIfNode *n) { DefaultVisit(n); }
	virtual void visit(ForStatementNode *n) { DefaultVisit(n); }
	virtual void visit(ForStatementNoShortIfNode *n) { DefaultVisit(n); }
	virtual void visit(ForInitNode *n) { DefaultVisit(n); }
	virtual void visit(ForUpdateNode *n) { DefaultVisit(n); }
	virtual void visit(ReturnStatementNode *n) { DefaultVisit(n); }
	virtual void visit(PrimaryNode *n) { DefaultVisit(n); }
	virtual void visit(PrimaryNoNewArrayNode *n) { DefaultVisit(n); }
	virtual void visit(ClassInstanceCreationExpressionNode *n) { DefaultVisit(n); }
	virtual void visit(ClassInstanceCreationExpressionWithoutArgumentsNode *n) { DefaultVisit(n); }
	virtual void visit(ArgumentListNode *n) { DefaultVisit(n); }
	virtual void visit(ArrayCreationExpressionNode *n) { DefaultVisit(n); }
	virtual void visit(DimExprNode *n) { DefaultVisit(n); }
	virtual void visit(FieldAccessNode *n) { DefaultVisit(n); }
	virtual void visit(MethodInvocationNode *n) { DefaultVisit(n); }
	virtual void visit(MethodInvocationWithoutArgumentsNode *n) { DefaultVisit(n); }
	virtual void visit(ArrayAccessNode *n) { DefaultVisit(n); }
	virtual void visit(ExpressionNode *n) { DefaultVisit(n); }
	virtual void visit(AssignmentNode *n) { DefaultVisit(n); }
	virtual void visit(LeftHandSideNode *n) { DefaultVisit(n); }
	virtual void visit(ConditionalOrExpressionNode *n) { DefaultVisit(n); }
	virtual void visit(ConditionalAndExpressionNode *n) { DefaultVisit(n); }
	virtual void visit(InclusiveOrExpressionNode *n) { DefaultVisit(n); }
	virtual void visit(ExclusiveOrExpressionNode *n) { DefaultVisit(n); }
	virtual void visit(AndExpressionNode *n) { DefaultVisit(n); }
	virtual void visit(EqualityExpressionNode *n) { DefaultVisit(n); }
	virtual void visit(RelationalExpressionNode *n) { DefaultVisit(n); }
	virtual void visit(AdditiveExpressionNode *n) { DefaultVisit(n); }
	virtual void visit(MultiplicativeExpressionNode *n) { DefaultVisit(n); }
	virtual void visit(UnaryExpressionNode *n) { DefaultVisit(n); }
	virtual void visit(UnaryExpressionNotPlusMinusNode *n) { DefaultVisit(n); }
	virtual void visit(PostfixExpressionNode *n) { DefaultVisit(n); }
	virtual void visit(CastExpressionNode *n) { DefaultVisit(n); }
	virtual void visit(ClassTypeNode *n) { DefaultVisit(n); }
	virtual void visit(InterfaceTypeNode *n) { DefaultVisit(n); }
	virtual void visit(TypeNode *n) { DefaultVisit(n); }
	virtual void visit(PrimitiveTypeNode *n) { DefaultVisit(n); }
	virtual void visit(NumericTypeNode *n) { DefaultVisit(n); }
	virtual void visit(IntegralTypeNode *n) { DefaultVisit(n); }
	virtual void visit(ReferenceTypeNode *n) { DefaultVisit(n); }
	virtual void visit(ClassOrInterfaceTypeNode *n) { DefaultVisit(n); }
	virtual void visit(ArrayTypeNode *n) { DefaultVisit(n); }
	virtual void visit(PrimitiveArrayTypeNode *n) { DefaultVisit(n); }
	virtual void visit(ObjectArrayTypeNode *n) { DefaultVisit(n); }
	virtual void visit(NameNode *n) { DefaultVisit(n); }
	virtual void visit(SimpleNameNode *n) { DefaultVisit(n); }
	virtual void visit(QualifiedNameNode *n) { DefaultVisit(n); }
	virtual void visit(LiteralNode *n) { DefaultVisit(n); }
	virtual void visit(IntegerLiteralNode *n) { DefaultVisit(n); }
	virtual void visit(BooleanLiteralNode *n) { DefaultVisit(n); }
	virtual void visit(CharacterLiteralNode *n) { DefaultVisit(n); }
	virtual void visit(StringLiteralNode *n) { DefaultVisit(n); }
	virtual void visit(NullLiteralNode *n) { DefaultVisit(n); }
};

struct WeedingVisitor : NodeVisitor {
	WeedingVisitor(std::string);

	bool Break() { return !isValid; }

	bool IsValid() { return isValid; }
	
	/* aggregate data from the visitor */
	void visit(CompilationUnitNode *);

	/* Things with modifiers */
	void visit(ClassDeclarationNode *);
	void visit(FieldDeclarationNode *);
	void visit(MethodDeclarationNode *);
	void visit(ConstructorDeclarationNode *);
	void visit(InterfaceDeclarationNode *);
	void visit(AbstractMethodDeclarationNode *);

	/* Weed cast expressions that are invalid */
	void visit(CastExpressionNode *);

	/* Check that integers are in range */
	void visit(IntegerLiteralNode *);

protected:
	bool isValid;
	std::string typeName;
	bool isClass;
	unsigned int constructorCount;
};

struct CompressionVisitor : NodeVisitor {
	CompressionVisitor() : NodeVisitor(Post), current_is_gone(false) {}

	bool Break() {
		bool val = current_is_gone;
		current_is_gone = false;
		return val;
	}

	bool current_is_gone;

	void visit(CompilationUnitNode *);
	void visit(ClassDeclarationNode *);
	void visit(ModifiersNode *);
	void visit(VariableDeclaratorNode *);
	void visit(MethodHeaderNode *);
	void visit(FormalParameterListNode *);
	void visit(ConstructorDeclarationNode *);
	void visit(InterfaceDeclarationNode *);
	void visit(BlockNode *);
	void visit(BlockStatementNode*);
	void visit(LocalVariableDeclarationNode *);
	void visit(ClassInstanceCreationExpressionNode*);
	void visit(ArgumentListNode *);
	void visit(ArrayCreationExpressionNode*);
	void visit(CastExpressionNode*);
	void visit(TypeNode *);
	void visit(ReferenceTypeNode *);
	void visit(QualifiedNameNode *);
	void visit(SimpleNameNode *);
	void visit(LiteralNode *);

	void visit(StatementNode *);
	void visit(IfStatementNode *);
	void visit(ForStatementNode *);

	void visit(ConditionalOrExpressionNode *);
	void visit(ConditionalAndExpressionNode *);
	void visit(InclusiveOrExpressionNode *);
	void visit(ExclusiveOrExpressionNode *);
	void visit(AndExpressionNode *);
	void visit(EqualityExpressionNode *);
	void visit(RelationalExpressionNode *);
	void visit(AdditiveExpressionNode *);
	void visit(MultiplicativeExpressionNode *);
	void visit(UnaryExpressionNode*);
	void visit(UnaryExpressionNotPlusMinusNode*);
	void visit(PostfixExpressionNode*);
	void visit(PrimaryNode*);
	void visit(PrimaryNoNewArrayNode*);
};

struct FillVisitor : NodeVisitor {
	FillVisitor() : NodeVisitor(Post) {}

	ClassDeclarationNode *current_class;
	MethodDeclarationNode * current_method;

	void visit(PackageDeclarationNode*);
	void visit(ClassDeclarationNode *);
	void visit(FieldDeclarationNode *);
	void visit(MethodDeclarationNode *);
	void visit(FormalParameterNode *);
	void visit(ConstructorDeclarationNode *);
	void visit(InterfaceDeclarationNode *);
	void visit(AbstractMethodDeclarationNode *);
	void visit(LocalVariableDeclarationNode *);
	void visit(ClassInstanceCreationExpressionNode*);
	void visit(ArrayCreationExpressionNode *);
	void visit(CastExpressionNode *);
	void visit(ClassTypeNode *);
	void visit(InterfaceTypeNode *);
	void visit(ReferenceTypeNode *);
};

struct ShrinkToFitVisitor : NodeVisitor {
	ShrinkToFitVisitor() : NodeVisitor(Post) {}
	void DefaultVisit(ParseNode *n) {
		//if (n->IsParent()) ((ParentNode*)n)->children.shrink_to_fit();
	}
};

struct EnvironmentBuildingVisitor : NodeVisitor {
	EnvironmentBuildingVisitor() : NodeVisitor(Pre), error(false), current_package_name(std::string()) {}

	bool Break() { return error; }

	std::map<std::string, std::set<ClassDeclarationNode*, compare_decls> > class_environment;

	std::string current_package_name;
	TypedNode *current_class;
	std::vector<TypedNode*> current_fields;
	std::vector<TypedNode*> current_methods;
	std::set<TypedNode*, compare_decls> current_params;
	std::set<TypedNode*, compare_decls> current_locals;

	bool error;

	void visit(RootNode*);
	void visit(CompilationUnitNode*);
	void visit(PackageDeclarationNode*);
	void visit(ClassDeclarationNode*);
	void visit(InterfaceDeclarationNode*);
	void visit(ConstructorDeclarationNode*);
	void visit(MethodDeclarationNode*);
	void visit(AbstractMethodDeclarationNode*);
	void visit(FieldDeclarationNode*);
	void visit(FormalParameterNode*);
	void visit(BlockNode*);
	void visit(LocalVariableDeclarationNode*);
	void visit(NameNode*);

};

struct TypeLinkingVisitor : NodeVisitor {
	TypeLinkingVisitor() : NodeVisitor(Post), error(false), local_needs_clearing(true) {}

	bool Break() { return error; }

	std::map<std::string, std::set<ClassDeclarationNode*, compare_decls> > class_environment;
	bool local_needs_clearing;
	std::map<std::string, std::set<std::string> > single_type_imports;
	std::set<std::string> type_on_demand_packages;

	std::string current_package;
	ClassDeclarationNode *current_class;
	EnvironmentNode *current_method;

	bool error;

	void visit(TypedNode*);

	void visit(RootNode*);
	void visit(PackageDeclarationNode*);
	void visit(SingleTypeImportDeclarationNode*);
	void visit(TypeImportOnDemandDeclarationNode*);
	void visit(ClassDeclarationNode*);
	void visit(InterfaceDeclarationNode*);
	void visit(ConstructorDeclarationNode*);
	void visit(MethodDeclarationNode*);
	void visit(AbstractMethodDeclarationNode*);
	void visit(FieldDeclarationNode*);
	void visit(FormalParameterNode*);
	void visit(LocalVariableDeclarationNode*);
	void visit(ClassInstanceCreationExpressionNode*);
	void visit(ArrayCreationExpressionNode*);
	void visit(CastExpressionNode *n);
	void visit(ClassTypeNode *);
	void visit(InterfaceTypeNode *);
	void visit(ReferenceTypeNode *);

	void visit(NameNode *);
private:
	ClassDeclarationNode* Get(std::string, std::string);
	ClassDeclarationNode* Get(std::string);
	bool PrefixResolves(std::string);
	void Clean();

};

struct HierarchyCheckingVisitor : NodeVisitor {
	HierarchyCheckingVisitor() : NodeVisitor(Post), error(false) {}
	
	bool Break() { return error; }

	std::set<ClassDeclarationNode*> resolved_inheritance;
	bool error;

	void visit(CompilationUnitNode *);
	void visit(ClassDeclarationNode *);
	void visit(InterfaceDeclarationNode *);
private:
	void CheapCheck(ClassDeclarationNode *);
	void CheapCheck(InterfaceDeclarationNode *);

	void CheckStructure(ClassDeclarationNode *, std::set<DeclarationNode*>&);
	void CheckStructure(InterfaceDeclarationNode *, std::set<DeclarationNode*>&);

	void InheritMethods(ClassDeclarationNode *, std::set<MethodDeclarationNode*, compare_decls>&);
	std::set<MethodDeclarationNode*, compare_decls> GetMethods(ClassDeclarationNode *);
};

struct CheckingVisitor : NodeVisitor {
	CheckingVisitor(TraverseType t) : NodeVisitor(t) {}

	ClassDeclarationNode* GetContainingClassFor(ParseNode*);
	bool CanAccessMember(ModifiedNode*, ParseNode*, ClassDeclarationNode*);
	bool CanAccessConstructor(ModifiedNode*, ParseNode*);
};

struct DisambiguateVisitor : CheckingVisitor {
	DisambiguateVisitor() : CheckingVisitor(Post), error(false), name_is_method_invocation(false) {}

	bool Break() { return error; }

	ClassDeclarationNode *current_class;
	MethodDeclarationNode *current_method;

	std::set<TypedNode*, compare_decls> declared_fields;
	DeclarationNode *current_field;

	bool error, name_is_method_invocation;

	void visit(ClassDeclarationNode *);
	void visit(ConstructorDeclarationNode *);
	void visit(MethodDeclarationNode *);
	void visit(MethodInvocationNode *);

	void visit(FieldDeclarationNode *);
	void visit(LocalVariableDeclarationNode *);

	void visit(NameNode *);
};

struct TypeCheckVisitor : CheckingVisitor {
	TypeCheckVisitor() : CheckingVisitor(Pre), error(false), current_class(0x0) {}
	bool Break() { return error; }

	ClassDeclarationNode* TypeCheckGetContainingClass(ParentNode *n) {
		if (current_class) return current_class;
		return current_class = GetContainingClassFor(n);
	}

	std::string BuildArgumentSignature(ParentNode *);

	bool error;
	std::stack<TypeMetaReference> metas;
	std::stack<TypeMetaReference> conditional_metas;

	ClassDeclarationNode *current_class;

	//After the class has been processed, it cleans out data used during the processing
	void visit(ClassDeclarationNode*) { 
		current_class = 0x0; 
	}

	//After the method has been processed, clean out the remaining metas, because the stack is variable
	void visit(MethodDeclarationNode*) { while (!metas.empty()) metas.pop(); }
	void visit(ConstructorDeclarationNode*);
	void visit(FieldDeclarationNode*);

	void visit(IfStatementNode*);
	void visit(IfThenElseStatementNode*);
	void visit(ForStatementNode*);
	void visit(WhileStatementNode*);

	void visit(ExpressionNode*);

	void visit(ConditionalOrExpressionNode *);
	void visit(ConditionalAndExpressionNode *);
	void visit(InclusiveOrExpressionNode *);
	void visit(ExclusiveOrExpressionNode *);
	void visit(AndExpressionNode *);
	void visit(EqualityExpressionNode *);
	void visit(RelationalExpressionNode *);
	void visit(AdditiveExpressionNode *);
	void visit(MultiplicativeExpressionNode *);
	void visit(UnaryExpressionNode *);
	void visit(UnaryExpressionNotPlusMinusNode *);
	void visit(LocalVariableDeclarationNode *);
	void visit(AssignmentNode *);
	void visit(CastExpressionNode *);
	void visit(ReturnStatementNode *);

	void visit(PrimaryNoNewArrayNode *);
	void visit(ArrayCreationExpressionNode *);
	void visit(ClassInstanceCreationExpressionNode *);
	void visit(FieldAccessNode *);
	void visit(MethodInvocationNode *);
	void visit(ArrayAccessNode *);

	void visit(NameNode *);
	void visit(IntegerLiteralNode *);
	void visit(CharacterLiteralNode *);
	void visit(StringLiteralNode *);
	void visit(BooleanLiteralNode *);
	void visit(NullLiteralNode *);
};

/*
 * Reachability Analysis
 * ReachabilityVisitor finds each method body and from there the node
 * accepts a StatementInOut which evaluates the statements in the 
 * body. It does so by recursively creating other StatementInOutNodes
 * that evaluate the inner statements.
 * base case is any non block non control flow statement or a return statement.
 */

struct ReachabilityTreeRestucturer : NodeVisitor {
	ReachabilityTreeRestucturer() : NodeVisitor(Post){}

	void visit(BooleanLiteralNode*n) {
		visitAddLiteralParent(n);
	}
	void visit(IntegerLiteralNode*n) {
		visitAddLiteralParent(n);
	}
	void visit(CharacterLiteralNode*n) {
		visitAddLiteralParent(n);
	}
	void visit(StringLiteralNode*n) {
		visitAddLiteralParent(n);
	}
	void visit(NullLiteralNode*n) {
		visitAddLiteralParent(n);
	}
	void visit(LocalVariableDeclarationNode*n);
protected:
	void visitAddLiteralParent(ParentNode*n);
};

enum {
	NO = 0,
	MAYBE = 1
};

struct StatementInOut : NodeVisitor {
	bool in, out, error, processed;
	StatementInOut(bool in) : NodeVisitor(Post), in(in), out(in), error(false), processed(false) {
		if (NO == in) error = true;
	}
	bool Break() { return error || processed; }
	void visit(StatementNode*);
	void visit(BlockNode*);
	void visit(IfStatementNode*);
	void visit(IfThenElseStatementNode *);
	void visit(WhileStatementNode*);
	void visit(ForStatementNode *);
	void visit(ReturnStatementNode*);
};

struct ReachabilityVisitor : NodeVisitor {
	bool error;

	ReachabilityVisitor() : NodeVisitor(Post), error(false){}

	void visit(ConstructorDeclarationNode*);
	void visit(MethodDeclarationNode*);
	
};

struct LeafDestroyerVisitor : NodeVisitor {
	LeafDestroyerVisitor() : NodeVisitor(Post) {}
	void DefaultVisit(ParseNode *n) {
		((ParentNode*)n)->DeleteLeafs();
	}

	void visit(EqualityExpressionNode *) {}
	void visit(RelationalExpressionNode*) {}
	void visit(AdditiveExpressionNode*) {}
	void visit(MultiplicativeExpressionNode*) {}
	void visit(NameNode*) {}
	void visit(LeafNode*) {}
	void visit(LiteralNode*) {}

};

struct PrintVisitor : NodeVisitor {
	PrintVisitor(std::ostream *out = &std::cout) : NodeVisitor(NodeVisitor::Post), out(out) {}

	std::map<ParseNode*, unsigned int> depth_map;
	std::ostream *out;

	void DefaultVisit(ParseNode *);

	void visit(LeafNode *);
	void visit(RootNode *);
	void visit(CompilationUnitNode *);
	void visit(IntegerLiteralNode *);
	void visit(BooleanLiteralNode *);
	void visit(CharacterLiteralNode *);
	void visit(StringLiteralNode *);
private:
	unsigned int _depth;
};

struct IndexVisitor : NodeVisitor {

	IndexVisitor() : NodeVisitor(Post), class_index(0), start_method(0x0) {}

	std::map<TypedNode*, unsigned int, compare_decls> interface_method_indexes;
	std::map<ClassDeclarationNode*, unsigned int> class_sizes;
	std::set<std::string> global_labels;
	MethodDeclarationNode *start_method;

	unsigned int class_index;

	void visit(RootNode*);
	void visit(ClassDeclarationNode*);
};

struct CodeGeneratingVisitor : NodeVisitor {
	CodeGeneratingVisitor(IndexVisitor &);

	bool Break() {
		bool b = return_to_parent;
		return_to_parent = false;
		return b;
	}


	bool error;
	bool return_to_parent;

	std::ofstream start_file_out;
	std::ofstream class_file_out;
	std::ofstream *context_file_out;

	std::map<ClassDeclarationNode*, std::map<ClassDeclarationNode*, bool> > subtype_mapping;
	std::set<std::string> global_labels;
	MethodDeclarationNode *start_method;

	void visit(RootNode *);
	void visit(ClassDeclarationNode *);
	void visit(FieldDeclarationNode*);
	void visit(ExpressionNode*);

	void visit(AdditiveExpressionNode *);
	void visit(MultiplicativeExpressionNode *);
	void visit(RelationalExpressionNode *);
	void visit(EqualityExpressionNode *);
	void visit(ConditionalAndExpressionNode *);
	void visit(ConditionalOrExpressionNode *);
	void visit(AndExpressionNode *);
	void visit(InclusiveOrExpressionNode *);
	void visit(UnaryExpressionNotPlusMinusNode *);
	void visit(UnaryExpressionNode *);
	void visit(IfStatementNode *);
	void visit(IfThenElseStatementNode *);
	void visit(WhileStatementNode *);
	void visit(ForStatementNode *);

	void visit(CastExpressionNode *);
	
	void visit(PrimaryNoNewArrayNode *);
	void visit(IntegerLiteralNode *);
	void visit(CharacterLiteralNode *);
	void visit(BooleanLiteralNode *);
	void visit(NullLiteralNode *);
	void visit(StringLiteralNode *);

	/* Return addresses for values */
	void visit(NameNode *);
	void visit(MethodInvocationNode*);
	void visit(ArrayAccessNode*);
	void visit(FieldAccessNode*);

	/* Assignment */
	void visit(LocalVariableDeclarationNode*);
	void visit(AssignmentNode*);

	std::string CreateLabelWithBase(std::string);
	std::string CreateLabelWithBase(std::string, int&);

	//Evaluates the left child and stores the result in eax and evaluates the right child and stores the value in ebx
	void BinaryOperation_ResolveChildren(ParseNode*, ParseNode*);

	/*
	 * Object creation
	 */
	std::map<ClassDeclarationNode*, unsigned int> class_sizes;
	void visit(ClassInstanceCreationExpressionNode*);
	void visit(ArrayCreationExpressionNode*);

	/*
	 * Method environment creation
	 */
	unsigned int param_index;
	std::string curEndLabel;
	void visit(MethodDeclarationNode*);
	void visit(ConstructorDeclarationNode*);
	void visit(FormalParameterNode*);
	void visit(ReturnStatementNode*);
};

struct VariableOffestVisitor : NodeVisitor {
	int offset;
	std::ofstream& file_out;
	VariableOffestVisitor(std::ofstream& file) : NodeVisitor(NodeVisitor::Post), offset(1), file_out(file){}
	void visit(LocalVariableDeclarationNode*);
};

struct EnvironmentVisitor : NodeVisitor {
	EnvironmentVisitor(std::ostream &out = std::cout) : NodeVisitor(NodeVisitor::Post), out(out) {}

	std::ostream &out;
	void DefaultVisit(ParseNode *);

	void visit(ClassDeclarationNode *);
	void visit(MethodDeclarationNode *);

	
private:
};



#endif